package com.vilen.learn.java7.V4;

/**
 * Created by vilen on 2017/9/24.
 * 死锁
 * 两个线程都说自己收到了更新，但它俩谁都不会以备份线程的身份确认收到了更新。
 * 因为每个线程在确认方法能够确认之前都要求另外一个线程释放线程锁
 */
public class DeadlockMicroBlogNode implements SimpleMicroBlogNode {

    private static Update getUpdate(String s) {
        Update.Builder b = new Update.Builder();
        b.updateText(s).author(new Author("Ben"));

        return b.build();
    }

    private final String ident;

    public DeadlockMicroBlogNode(String ident_) {
        ident = ident_;
    }

    @Override
    public synchronized void propagateUpdate(Update upd_, SimpleMicroBlogNode backup_) {
        System.out.println(ident + ": recvd: " + upd_.getUpdateText()
                + " ; backup: " + backup_.getIdent());
        backup_.confirmUpdate(this, upd_);
    }

    @Override
    public synchronized void confirmUpdate(SimpleMicroBlogNode other_, Update update_) {
        System.out.println(ident + ": recvd confirm: " + update_.getUpdateText()
                + " from " + other_.getIdent());
    }

    @Override
    public String getIdent() {
        return ident;
    }

    public static void main(String[] args) {
        final DeadlockMicroBlogNode local = new DeadlockMicroBlogNode("localhost:8888");
        final DeadlockMicroBlogNode other = new DeadlockMicroBlogNode("localhost:8988");

        final Update first = getUpdate("1");
        final Update second = getUpdate("2");

        new Thread(new Runnable() {
            @Override
            public void run() {
                local.propagateUpdate(first,other);
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                other.propagateUpdate(second, local);
            }
        }).start();

        // 有一个处理死锁的技巧，就是在所有线程中都以相同的顺序获取线程锁。在前例中，第一个线程以A、B的顺序获取锁，
        // 而第二个线程获取锁的顺序是B、A。如果两个线程都用A、B的顺序，死锁的情况就可以避免，
        // 因为第二个线程在第一个线程完成并释放锁之前会一直被阻塞住。
    }
}
